/**
* lumeng實用框架
* author : Lumeng
* email : zhengb302@163.com
*
*/
(function(window){

//緊跟著定義的這些變量用作閉包
var rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g,

	//空格
	space="\u0020",

	//本頁面的URL
	url=window.location.href,

	//本頁面的GET請求參數對
	search=window.location.search,

	//應用程序路徑
	appPath="/"+window.location.pathname.split("/")[1],

	//日期正則表達式
	datePattern=/^[1-9]\d{3}(-|\/)((0[1-9])|(1[0-2]))(-|\/)((0[1-9])|([12]\d)|(3[01]))$/,

	//時間正則表達式
	timePattern=/^(([01]\d)|(2[0-3])):[0-5]\d(:[0-5]\d)?$/,

	//XML 文档和节点序列化器，如果有(非IE瀏覽器)
	xmlSerializer=window.XMLSerializer ? new XMLSerializer() : null ,
	
	//複製常用的函數
	toString=Object.prototype.toString;

//lm 對象
var lm={
	version: "0.0.1"
};

//定義淺度複製方法
lm.extend=function(obj,cfg){
	if(obj){
		for(var p in cfg)
			obj[p]=cfg[p];
	}
	return obj;
};

//擴展Function的原型對象
lm.extend(Function.prototype, {

	//給一函數或方法創建攔截器
	//其實是代理函數(或方法)
	createInterceptor: function(fn){

		//此處的this是方法本身
		var method=this;

		return function(/*arg1,...*/){
			var _self=this,
				args=arguments;
			return fn.apply(_self||window,args) != false ?
				   method.apply(_self||window,args) :
				   null;
		};
	}
});

//擴展String的原型對象
lm.extend(String.prototype,{
	//去除字符串兩邊的空白
	trim: function(){
		return (this || "").replace( rtrim, "" );
	},

	//填充（左填充或右填充）
	pad: function( position, len, pad ){
		var ret=this,
			l=ret.length;

		//如果沒有提供第二個參數
		if( typeof pad == "undefined" )
			pad=space;

		if( typeof pad != "string" )
			throw "the padding character must be string!";

		//如果填充字符串的長度大於一
		if(pad.length>1)
			//取第一個
			pad=pad.charAt(0);

		if( l<=len )
			for(var t=len-l,i=0;i<t;i++){
				//左填充
				if( position == "left" )
					ret=pad+ret;
				//右填充
				else if( position == "right" )
					ret=ret+pad;
				else
					throw 'the position must be "left" or "right" !';
			}
		else
			ret=ret.substring(0,len);
		return ret;
	},

	//左填充
	lpad: function(len,pad){
		return this.pad("left",len,pad);
	},
	
	//右填充
	rpad: function(len,pad){
		return this.pad("right",len,pad);
	},

	//把字符串轉化為XML文檔
	toXML: function(){
		var xmlDoc;
		try{	//IE
			xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
			xmlDoc.async="false";
			xmlDoc.loadXML(this);
		}
		catch (e){		//Firefox
			try{
				var parser=new DOMParser();
				xmlDoc=parser.parseFromString(this,"text/xml");
			}
			catch(ee){
				xmlDoc=null;
			}
		}
		return xmlDoc;
	}
});

lm.extend(String,{
	empty : ""
});

/**
 * 可能是jQuery設計上的失誤，導致這些
 * 數組實用方法出現一點小Bug，在此創建
 * 一個攔截器用於修正此小Bug
 */
var arrayNoConflict=function(){

	//如果調用數組方法的對象不是數組
	if( !lm.isArray(this) )
		//則返回false，將會停止對數組方法的調用
		return false;
};

//擴展數組對象
lm.extend(Array.prototype,{

	//用於優雅地遍歷每一個數組元素，再也不用寫 $.each 了
	each: (function(callback){
		var _self=this;
		if(typeof callback != "function")
			return;
		for(var i=0;i<_self.length;i++){
			var ret=callback(i,_self[i]);

			//如果囘調函數返回的是false，則退出循環
			if(ret == false)
				break;
		}
		return this;
	}).createInterceptor(arrayNoConflict),

	/**
	 * 搜索數組，返回滿足條件的元素組成的數組
	 * filter 如果傳入的元素滿足條件，則此函數返回true
	 */
	search: (function(filter){
		var _self=this;
		var ret=[];
		for(var i=0;i<_self.length;i++){
			var result=filter(_self[i]);
			if(result==true)
				ret.push(_self[i]);
		}
		return ret;
	}).createInterceptor(arrayNoConflict),

	/**
	 * 返回數組中是否包含滿足條件的元素
	 * 如果包含，則返回true
	 * 否則返回false
	 */
	contains: (function(fn){
		var _self=this;
		for(var i=0,len=_self.length;i<len;i++)
			//如果某個元素符合條件，則返回true
			if( fn(_self[i])== true )
				return true;
		
		//如果一個都不包含，則返回false
		return false;
	}).createInterceptor(arrayNoConflict),

	//合併second數組
	merge: (function( second ){
		var _self=this, i=_self.length, j=0;
		for(var len=second.length;j<len;i++, j++)
			_self[i]=second[j];
		return this;
	}).createInterceptor(arrayNoConflict),

	/**
	 * 刪除符合條件或給定的數組元素
	 * fn 如果傳入的元素滿足條件，則此函數返回true
	 * array 可以刪除傳入的數組，但這要求數組元素為普通數據類型
	 * x1,x2,x3 普通元素列表，這也要求數組元素為普通數據類型
	 * 最後一個參數可能是用來指示是否只刪除一次
	 */
	remove: (function(/* fn or array or elements*/){
		var _self=this, args=arguments,
			first=args[0], last=args[args.length-1];
		var removeOnce=false;

		//如果是布爾類型且為true
		if( lm.isBoolean(last) && last )
			removeOnce=true;

		//如果是函數
		if( lm.isFunction(first) ){
			var fn=first;
			for(var i=0;i<_self.length;i++){
				var result=fn(_self[i]);
				if(result==true){
					_self.splice(i,1);
					i--;

					//如果是刪除找到的第一個元素
					if(removeOnce)
						break;
				}
			}
		}
		//如果是數組
		else if( lm.isArray(first) ){
			first.each(function(i,el){

				//刪除在包含在first中的_self的元素
				_self.remove(function(ele){ return ele==el; }, removeOnce);

			});
		}
		//如果參數是普通的元素，如 remove(1,2,3);
		else{
			//把參數轉化為數組
			var myArgs=[].merge(args);
			if( lm.isBoolean(last) )
				myArgs.length--;
			_self.remove(myArgs, removeOnce);
		}
		return this;
	}).createInterceptor(arrayNoConflict),

	/**
	 * 刪除找到的第一個元素
	 */
	removeOnce: (function(/*fn or single element*/){
		var _self=this, args=[].merge(arguments);

		//添加是否刪除一次參數
		args.push(true);

		Array.prototype.remove.apply(_self, args);
		return this;
	}).createInterceptor(arrayNoConflict),

	/**
	 * 在數組指定位置插入一個或多個元素
	 * 指定位置之後的元素將會後移
	 */
	insert: (function(/*i,ele1,ele2,...,elex*/){
		var index=arguments[0], args=[index,0];

		//合併參數，并刪掉多餘的index
		args.merge(arguments).splice(2,1);

		Array.prototype.splice.apply(this,args);
		return this;
	}).createInterceptor(arrayNoConflict),

	/**
	 * 清空數組元素
	 */
	empty: (function(){
		this.length=0;
		return this;
	}).createInterceptor(arrayNoConflict),

	/**
	 * 返回數組的最後一個元素
	 * 如果數組的長度為0，則返回undefined
	 */
	last: (function(){

		return (this.length!=0) ? this[this.length-1] : undefined;

	}).createInterceptor(arrayNoConflict)
});

//瀏覽器信息
var browser={};

//初始化browser對象
(function(){
	var _self=this, nav = window.navigator;
    var info = nav.appCodeName + " " + nav.appName + " " + nav.appVersion + " " + nav.userAgent;
    var p = {
        chrome: /Chrome\/\d+\.\d+\.\d+\.\d+/,
        ie: /MSIE\u0020\d+\.\d+/,
        safari: /Version\/\d+\.\d+\.\d+\u0020Safari/,
        firefox: /Firefox\/\d+\.\d+(\.\d+)?/,
        opera: /Presto\/\d+\.\d+\.\d+\u0020Version\/\d+\.\d+/
    };
    var name = "未知", version = "未知", resultArray;
    if ((resultArray = info.match(p["ie"])) != null) {
        var t = resultArray[0];
        name = "IE";
        version = t.split(" ")[1];
    }
    else if ((resultArray = info.match(p["firefox"])) != null) {
        var t = resultArray[0];
        name = "Firefox";
        version = t.split("/")[1];
    }
    else if ((resultArray = info.match(p["chrome"])) != null) {
        var t = resultArray[0];
        name = "Google Chrome";
        version = t.split("/")[1];
    }
    else if ((resultArray = info.match(p["safari"])) != null) {		//有Safari字符串的也有可能是Chrome瀏覽器
        var t = resultArray[0];
        name = "Apple Safari";
        version = t.split("/")[1].split(" ")[0];
    }
    else if ((resultArray = info.match(p["opera"])) != null) {
        var t = resultArray[0];
        name = "Opera";
        version = t.split(" ")[1].split("/")[1];
    }
	_self["name"]=name;
	_self["version"]=version;
}).call(browser);

//擴展browser對象
lm.extend( browser, {
	toString: function(){
		return this.name+" "+this.version;
	}
});

var request= {
	getParameter: function(name){
		name=name||String.empty;
		//this[name]==""的情況是："param="，只有
		//參數沒有值，這裡也作為一種正常情況
		if( this[name]||this[name]=="" )
			return this[name];
		else
			return undefined;
	},

	//返回本頁面的url
	getUrl: function(){
		return url;
	},

	getSearch: function(){
		return search;
	},

	//返回應用程序路徑
	getAppPath: function(){
		return appPath;
	},

	/**
	 * 獲得參數名為name的參數值，并把
	 * 它轉化為 布爾值 之後返回
	 */
	getBool: function(name){
		var v=this.getParameter(name);
		if( v==undefined )
			return v;
		if( v=="true")
			return true;
		else if( v=="false" )
			return false;
		else
			throw "the value of parameter \""+name+"\""+
				  " can't be converted to boolean!";
	}
};

//初始化 request 對象
(function(){
	if(search==String.empty)
		return;
	var paramString=search.split("?")[1];
	var params=paramString.split("&");
	for(var i=0;i<params.length;i++){
		var keyValueString=params[i];
		if(keyValueString != ""){
			var keyValue=keyValueString.split("="),
				key= keyValue[0],
				value= keyValue[1];

			//參數字符串中可能包含 %uXXXX，則用unescape解碼
			key=/%u\w{4}/.test(key) ? unescape(key) : decodeURIComponent(key);
			value=/%u\w{4}/.test(value) ? unescape(value) : decodeURIComponent(value);

			this[key]=value;
		}
	}
}).call(request);

//cookie對象
var cookie = {
	get: function(name) {
		if (document.cookie.length > 0) {
			var start = document.cookie.indexOf(name + "=");
			if (start != -1) {
				start = start + name.length + 1;
				var end = document.cookie.indexOf(";", start);
				(end == -1) && (end = document.cookie.length);
				return unescape(document.cookie.substring(start, end));
			}
		}
		return "";
	},

	/**
	 * 設置cookie
	 * name cookie名
	 * value cookie值
	 * expireDays 過期的天數
	 */
	set: function(name, value, expireDays) {
		var str = name + "=" + escape(value);
		if (typeof expireDays=="number" ) {
			var exDate = new Date();
			exDate.setDate(exDate.getDate() + expireDays);
			str += ";expires=" + exDate.toGMTString();
		}
		document.cookie = str;
	}
};

//把XML元素或節點序列化為字符串(閉包)
var xmlToString = function(node){
	return xmlSerializer ? 
			xmlSerializer.serializeToString(node) : 
			(node.xml ? node.xml : "");
};

//如果不是IE瀏覽器，則為xml document和element節點添加selectNodes方法和selectSingleNode方法
if(browser.name != "IE" ){

	//文檔節點 selectNodes
	XMLDocument.prototype.selectNodes=function(path){
		var xpe=this.createExpression(path,null);
		var result=xpe.evaluate(this,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null);
		var next,ret=[];
		while( (next=result.iterateNext())!=null )
			ret.push(next);
		//返回節點列表
		return ret;
	};

	//文檔節點 selectSingleNode
	XMLDocument.prototype.selectSingleNode=function(path){
		var xpe=this.createExpression(path,null);
		var result=xpe.evaluate(this,XPathResult.FIRST_ORDERED_NODE_TYPE,null);
		//返回獲取的單個節點
		return result.singleNodeValue;
	};

	//定義文檔節點的 xml屬性，返回節點序列化后的字符串
	XMLDocument.prototype.__defineGetter__("xml", function(){
		return xmlToString(this);
	});

	//元素節點 selectNodes
	Element.prototype.selectNodes=function(path){
		var xpe=this.ownerDocument.createExpression(path,null);
		var result=xpe.evaluate(this,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null);
		var next,ret=[];
		while( (next=result.iterateNext())!=null )
			ret.push(next);
		//返回節點列表
		return ret;
	};

	//元素節點 selectSingleNode
	Element.prototype.selectSingleNode=function(path){
		var xpe=this.ownerDocument.createExpression(path,null);
		var result=xpe.evaluate(this,XPathResult.FIRST_ORDERED_NODE_TYPE,null);
		//返回獲取的單個節點
		return result.singleNodeValue;
	};

	//定義元素節點的 xml屬性，返回節點序列化后的字符串
	Element.prototype.__defineGetter__("xml", function(){
		return xmlToString(this);
	});

	//取得元素的inner text
	Element.prototype.__defineGetter__("text",function(){
		var childs=this.childNodes;
		if(childs.length > 1)
			//無意義的操作
			return null;
		else if(childs.length==1){
			if(childs[0].nodeType==3 || childs[0].nodeType==4 )
				return childs[0].nodeValue;
			else
				//無意義的操作
				return null;
		}
		//如果沒有子節點
		else
			return "";
	});

	//設置元素的inner text
	Element.prototype.__defineSetter__("text",function(text){
		var textNode=document.createTextNode(text);
		
		//如果有子節點，則先刪除之，再……
		var childs=this.childNodes;
		
		//循環len次，每次都刪除第一個，則可盡數刪除
		for(var i=0,len=childs.length;i<len;i++){
			this.removeChild(childs[0]);
		}
		
		this.appendChild(textNode);
	});
}

//擴展window對象
lm.extend(window,{
	request: request,

	/**
	 * eg. cookie("username","zhengb302");
	 *	   cookie("username");
	 * this will be "zhengb302"
	 */
	cookie: function(/*name[,value][,expireDays]*/) {
		var args = arguments, name = args[0],
			value = args[1], expireDays = args[2];
		return value == undefined ? cookie.get(name) :
			cookie.set(name, value, expireDays);
	}
});

//擴張 lm 自己
lm.extend(lm,{

	//包含瀏覽器信息的對象，name&version
	browser: browser,

	id: function(id){
		return document.getElementById(id);
	},

	//創建dom元素(Create Element)
	ce: function(tagName){
		var ret;
		if( tagName=="text"||tagName=="password"||tagName=="radio"||
			  tagName=="checkbox"||tagName=="submit"||tagName=="button"||
			  tagName=="reset"||tagName=="image"||tagName=="file"||
			  tagName=="hidden" ){

			ret=document.createElement("input");
			ret.type=tagName;
			return ret;
		}
		else
			return document.createElement(tagName);
	},

	//創建文本dom節點(Create Text node)
	ct: function(text){
		return document.createTextNode(text);
	},

	//創建文檔片段對象(Create document Fragment)
	cf: function(){
		return document.createDocumentFragment();
	},

	//將對象序列化為url參數的方法
	param: function(obj){
		var ret="";
		if(typeof obj != "object")		//目前只能序列化對象
			return "";
		for(var p in obj){
			if(typeof obj[p] == "object")
				continue;
			ret=ret+encodeURIComponent(p)+"="+encodeURIComponent(obj[p])+"&";
		}
		if(ret != "")
			ret=ret.substring(0,ret.length-1);
		return ret;			//eg. age=12&sex=male&name=zhangsan
	},

	//把一個JSON字符串轉化為JSON對象（或數組）
	parseJSON: function(str){
		if(!str||typeof str != "string")
			return null;
		str=str.trim();
		try{
			return window.JSON&&window.JSON.parse ?
				window.JSON.parse(str) :
				(new Function("return "+str))();
		}
		catch(e){
			return null;
		}
	},

	//把一個XML字符串轉化為XML文檔對象
	//建議直接使用 str.toXML()，保留此方法是爲了兼容以前的程式
	parseXML: function(str){
		return str.toXML();
	},
	
	//檢測傳入的參數是否為數組
	isArray: function( a ){
		return toString.call(a) == "[object Array]";
	},

	//檢測傳入的參數是否為函數
	isFunction: function( fn ){
		return toString.call(fn) == "[object Function]";
	},

	//檢測傳入的參數是否為布爾類型
	isBoolean: function( a ){
		return toString.call(a) == "[object Boolean]";
	},

	//檢測傳入的字串是否為日期值
	isDate: function( d ){
		if( typeof(d) != "string" )
			return false;
		if( !datePattern.test(d) )
			return false;

		//如果字符串中同時存在 / 或 -
		if( (d.indexOf("/")!=-1) &&
			(d.indexOf("-")!=-1) )
			return false;

		var arr=d.split(/[-\/]/),
			year=parseInt(arr[0]),
			month=parseInt(arr[1]),
			day=parseInt(arr[2]);
		if( (month==2||month==4||month==6||month==9||month==11)
			&& day==31 )
			return false;
		if( month==2 ){
			if( year%4==0 && day>29 )
				return false;
			else if( year%4!=0 && day>28 )
				return false;
		}
		return true;
	},

	//檢測傳入的字串是否為時間值
	isTime: function( t ){
		if( typeof(t) != "string" )
			return false;
		if( !timePattern.test(t) )
			return false;
		return true;
	}
});

//把 lm 賦給 window 對象
window.lm=lm;

})(window);